package handler

import (
	"ehsm_kms/api"
	"ehsm_kms/internal/ehsm"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/iancoleman/orderedmap"
	"sort"
)

func (h *Handler) generateQuote(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			Challenge string `json:"challenge" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.Resp)
	err := ehsm.GenerateQuoteAction.Call(ehsm.GenerateQuotePayload{
		Challenge: req.Payload.Challenge,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) verifyQuote(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			PolicyId string `json:"policyId,omitempty" binding:"omitempty"`
			Quote    string `json:"quote" binding:"required"`
			Nonce    string `json:"nonce" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	var mE, mS string
	var err error
	if req.Payload.PolicyId != "" {
		mE, mS, err = h.quoteRep.FindByPolicyId(ctx, req.Appid, req.Payload.PolicyId)
		if err != nil {
			api.HandleError(ctx, 400, err, nil)
			ctx.Abort()
			return
		}
	}
	resp := new(ehsm.VerifyQuoteResp)
	err = ehsm.VerifyQuoteAction.Call(ehsm.VerifyQuotePayload{
		Quote:     req.Payload.Quote,
		Nonce:     req.Payload.Nonce,
		MrSigner:  mS,
		MrEnclave: mE,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	if mE != "" {
		resp.Result.MrEnclave = mE
	}
	if mS != "" {
		resp.Result.MrSigner = mS
	}

	_r, _ := json.Marshal(resp.Result)
	om := orderedmap.New()
	err = om.UnmarshalJSON(_r)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	resp.Result.Sign, err = h.userRep.GenHmac(ctx, req.Appid, []byte(paramsSortStr(om)))
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) uploadQuotePolicy(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			MrEnclave string `json:"mr_enclave" binding:"required"`
			MrSigner  string `json:"mr_signer" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	err := h.quoteRep.Store(ctx, req.Appid, req.Payload.MrEnclave, req.Payload.MrSigner)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleSuccess(ctx, nil)
}

func (h *Handler) getQuotePolicy(ctx *gin.Context) {

	req := struct {
		Req
		Payload struct {
			PolicyId string `json:"policyId,omitempty" binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	m, err := h.quoteRep.FindModelByPolicyId(ctx, req.Appid, req.Payload.PolicyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	api.HandleSuccess(ctx, gin.H{
		"mr_enclave": m.MrEnclave,
		"mr_signer":  m.MrSigner,
		"createTime": m.CreateTime,
	})
}

func paramsSortStr(signParams *orderedmap.OrderedMap) string {
	var str string
	sortedSignParams := sortMap(signParams)
	for _, k := range sortedSignParams.Keys() {
		v, _ := sortedSignParams.Get(k)
		if k == "payload" {
			payload := v.(*orderedmap.OrderedMap)
			str += "&" + k + "=" + paramsSortStr(payload)
		} else {
			str += fmt.Sprintf("&%s=%v", k, v)
		}
	}
	if len(str) > 0 {
		str = str[1:] // Remove leading "&"
	}
	return str
}
func sortMap(oldmap *orderedmap.OrderedMap) *orderedmap.OrderedMap {
	newmap := orderedmap.New()
	keys := oldmap.Keys()
	sort.Strings(keys)
	for _, key := range keys {
		value, _ := oldmap.Get(key)
		newmap.Set(key, value)
	}
	return newmap
}
